﻿// --------------------------------------------------------------------------------------------------------------------- 
// <copyright file="Program.cs" company="Microsoft">
//   Copyright (c) Microsoft Corporation.  All rights reserved. THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
// </copyright>
// <summary>
//   Defines the Program type.
// </summary>
// ---------------------------------------------------------------------------------------------------------------------
namespace EulerProblemsCSharp
{
    using System;
    using System.Collections.Generic;
    using System.Diagnostics;
    using System.Globalization;

    using EulerProblemsCSharp.Problems;

    /// <summary>
    /// Program type.
    /// </summary>
    public static class Program
    {
        /// <summary>
        /// Entry point for console application.
        /// </summary>
        /// <param name="args">
        /// The arguments.
        /// </param>
        public static void Main(string[] args)
        {
            if (args == null || args.Length == 0)
            {
                foreach (var p in AllProblems())
                {
                    SolveProblem(p);                    
                }
            }
            else if (args[0] == "-perf")
            {
                foreach (var p in AllProblems())
                {
                    TimeProblem(p);
                }
            }
            else
            {
                foreach (var arg in args)
                {
                    int problemNumber;

                    if (Int32.TryParse(arg, out problemNumber))
                    {
                        var problemTypeName = String.Format(CultureInfo.InvariantCulture, "EulerProblemsCSharp.Problems.Problem{0}", problemNumber);

                        var problemType = Type.GetType(problemTypeName);
                        if (problemType == null)
                        {
                            throw new ArgumentException(String.Format(CultureInfo.InvariantCulture, "Unable to create instance of '{0}'", problemTypeName));
                        }

                        var problem = (ProblemBase)Activator.CreateInstance(problemType);
                        
                        SolveProblem(problem);
                    }
                    else
                    {
                        throw new ArgumentException(String.Format(CultureInfo.InvariantCulture, "Unknown argument '{0}'", arg));
                    }
                }
            }

            Console.Write("Press any key...");
            Console.ReadKey();
        }

        /// <summary>
        /// Calls Solve for a given ProblemBase derived class.
        /// </summary>
        /// <param name="problem">
        /// The problem.
        /// </param>
        private static void SolveProblem(ProblemBase problem)
        {
            Console.WriteLine("Problem {0}", problem.Number);
            Console.WriteLine(problem.Description);
            var answer = problem.Solve();
            Console.WriteLine("Answer: {0}", answer);
            Console.WriteLine();
        }

        /// <summary>
        /// Calls Solve for a given ProblemBase derived class, and times it.
        /// </summary>
        /// <param name="problem">
        /// The problem.
        /// </param>
        private static void TimeProblem(ProblemBase problem)
        {
            Console.WriteLine("Problem {0}", problem.Number);
            Console.WriteLine(problem.Description);
            
            var timer = new Stopwatch();
            timer.Start();   
                     
            var answer = problem.Solve();
            
            timer.Stop();

            Console.WriteLine("Answer: {0}. Time to solve problem: {1} ms", answer, timer.ElapsedMilliseconds);
            Console.WriteLine();
        }

        /// <summary>
        /// Returns a sequence of all problems
        /// </summary>
        /// <returns>
        /// Sequence of all problems.
        /// </returns>
        private static IEnumerable<ProblemBase> AllProblems()
        {            
            yield return new Problem1();
            yield return new Problem2();
            yield return new Problem3();
            yield return new Problem4();
            yield return new Problem5();
            yield return new Problem6();
            yield return new Problem7();
            yield return new Problem8();
            yield return new Problem10();
            yield return new Problem12();
            yield return new Problem13();
            yield return new Problem25();
            yield return new Problem27(); 
            yield return new Problem36();
            yield return new Problem40();                        
        }
    }
}